﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;
using System.Text.Json;
using NJson = Newtonsoft.Json;

namespace Test
{
    class Program
    {
        static object GetValueForIList(JsonElement srcData, Type type)
        {
            object result = null;
            if (type.FullName.StartsWith("System.Collections.Generic.IList"))
            {
                var subType = type.GetGenericArguments()[0];
                var gtype = Type.GetType("System.Collections.Generic.List`1").MakeGenericType(subType);
                IList robj = (IList)Activator.CreateInstance(gtype);
                var tobj=srcData.EnumerateArray().Select(it =>
                {
                    return GetValue(it, subType);
                }).ToArray();
                foreach(var elm in tobj)
                {
                    robj.Add(elm);
                }
                result = robj;
            }
            else if(type.GetInterface("System.Collections.IList") != null)
            {
                var subType = type.GetGenericArguments()[0];
                IList robj = (IList)Activator.CreateInstance(type);
                var tobj = srcData.EnumerateArray().Select(it =>
                {
                    return GetValue(it, subType);
                }).ToArray();
                foreach (var elm in tobj)
                {
                    robj.Add(elm);
                }
                result = robj;
            }
            return result;
        }
        static object GetValueForArray(JsonElement srcData, Type type)
        {
            object result = null;
            if (type.BaseType==typeof(Array))
            {
                var getMethodInfo = type.GetMethod("Get");
                var subType = getMethodInfo.ReturnType;
                Array robj=(Array)Activator.CreateInstance(type,srcData.GetArrayLength());
                
                srcData.EnumerateArray().Select(it =>
                {
                    return GetValue(it, subType);
                }).ToArray().CopyTo(robj,0);
                result = robj;
            }
            else
            {
                result = GetValueForIList(srcData, type);
            }
            return result;
        }
        static object GetValue(JsonElement srcData,Type type)
        {
            object result = null;

            switch (srcData.ValueKind)
            {
                case JsonValueKind.Null:
                    result = null;
                    break;
                case JsonValueKind.Number:
                    result = srcData.GetDouble();
                    result = Convert.ChangeType(result, type);
                    break;
                case JsonValueKind.False:
                    result = false;
                    break;
                case JsonValueKind.True:
                    result = true;
                    break;
                case JsonValueKind.Undefined:
                    result = null;
                    break;
                case JsonValueKind.String:
                    result = srcData.GetString();
                    break;
                case JsonValueKind.Object:
                    var ps=type.GetProperties();
                    result=Activator.CreateInstance(type);
                    foreach (var p in ps)
                    {
                        var val = GetValue(srcData.GetProperty(p.Name), p.PropertyType);
                        p.SetValue(result, val);                        
                    }
                    break;
                case JsonValueKind.Array:
                    result = GetValueForArray(srcData, type);
                    break;
            }
            return result;
        }
        static void Main(string[] args)
        {
            var t1 = new ServiceInvokeInfoIn();
            t1.Args = new int[] {1,2,3};
            var json = JsonSerializer.Serialize<ServiceInvokeInfoIn>(t1);
            var b = JsonSerializer.Deserialize<ServiceInvokeInfo>(json);
            var b2=NJson.JsonConvert.DeserializeObject<ServiceInvokeInfo>(json);
            //var r = GetValue((JsonElement)b.Args[0],typeof(List<UserInfo>));
            //var rname = r.GetType().Name;
        }
    }
    public class ServiceInvokeInfoIn
    {
        public string ServicePath { get; set; }
        public int[] Args { get; set; }
    }
    public class ServiceInvokeInfo
    {
        public string ServicePath { get; set; }
        public int[] Args { get; set; }
    }
    class UserInfo
    {
        public string Name { get; set; }
        public int Age { get; set; }
        public UserInfo Child { get; set; }
    }
}
